package opgave3;

public class Node<E extends Data> implements Clonable{
	E data;
	Node<E> parent, leftChild, rightChild;
	
	public Node(E data) {
		this(data, null);
	}
	
	public Node(E data, Node parent) {
		this.data = data == null ? null : (E) data.clone();
		this.parent = parent;
	}
	
	boolean isRoot() {
		return parent == null;
	}
	
	boolean hasLeftChild() {
		return leftChild != null;
	}
	
	boolean hasRightChild() {
		return rightChild != null;
	}
	
	boolean isInternal() {
		return leftChild != null || rightChild != null;
	}
	
	public void remove(E data) {
		int comparison = data.compareTo(this.data);
		if(comparison == 0) {
			if(hasLeftChild() && hasRightChild()) {
				if(Math.random() > 0.5) {
					this.data = rightChild.minValue();
					rightChild.remove(this.data);
				} else {
					this.data = leftChild.maxValue();
					leftChild.remove(this.data);
				}
			} else if(parent.leftChild == this) {
				if(hasLeftChild()) {
					parent.leftChild = leftChild;
					leftChild.parent = parent;
				} else {
					parent.leftChild = rightChild;
					if(hasRightChild()) {
						rightChild.parent = parent;
					}
				}
			} else if(parent.rightChild == this) {
				if(hasLeftChild()) {
					parent.rightChild = leftChild;
					leftChild.parent = parent;
				} else {
					parent.rightChild = rightChild;
					if(hasRightChild()) {
						rightChild.parent = parent;
					}
				}
			}
		} else if (comparison < 0) {
			leftChild.remove(data);
		} else {
			rightChild.remove(data);
		}
	}
	
	public E minValue() {
		if(!hasLeftChild()) {
			return data;
		} else {
			return leftChild.minValue();
		}
	}
	
	public E maxValue() {
		if(!hasRightChild()) {
			return data;
		} else {
			return rightChild.maxValue();
		}
	}
	
	public Node<E> clone() { 
		Node<E> result;
		
		try {
	        result = (Node<E>) super.clone();
	    } catch (CloneNotSupportedException e) {
	        throw new Error("Onmogelijk! instantie Knoop is niet Cloneable");
	    }

        result.data = data == null ? null : (E) data.clone();
        
        return result;
	}
}
